package com.wawayaya.bookreader.stroke.provider;

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.content.res.AssetManager;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;
import com.wawayaya.db.bookreader.StrokeDB;
import com.wawayaya.util.FileUtil;
import com.wawayaya.util.TLog;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class StrokeProvider extends ContentProvider {
    /// string for output debug filter
    public static final String TAG = "StrokeProvider";
    /// provider name
    public static final String PROVIDER_NAME = "com.wawayayareader.strokeprovider";
    /// base URI
    public static final Uri CONTENT_URI = Uri.parse("content://" + PROVIDER_NAME + "/stroke");
    /// dbFile's folder path
   // private static final String DB_PATH = "databases";
    /// for direct control table
    public static final int CHN_LIST = 1;
    /// for stroke of one Chinese word, one word may have many records(depend on its contours)
    public static final int CHN_CODE = 2;
    /// URI matcher
    public static final UriMatcher uriMatcher;
    /// predefined database' source file path: from SDCARD
    public static final String DB_SOURCE_PATH = "%s/creative/";

    static{
        uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        uriMatcher.addURI(PROVIDER_NAME, "stroke", CHN_LIST);
        uriMatcher.addURI(PROVIDER_NAME, "stroke/#", CHN_CODE);
    }
    /// access to stroke table
    private static StrokeDB mDB = null;
    /// file path to load, end with '/', parent folder of 'databases'
    private static String mloadPath = "";
    /// path of lib
    private static String mLibPath = "";
    /// to access assets
    private static AssetManager mAssetsManager = null;
    /// file list in asset/db
    private static String[] mAssetsDBFile = null;

    @Override
    public int delete(Uri arg0, String arg1, String[] arg2) {
        // TODO Auto-generated method stub
        // arg0 = uri
        // arg1 = selection
        // arg2 = selectionArgs
        int count=0;
        switch (uriMatcher.match(arg0)){
            case CHN_LIST:
                count = mDB.mstrokeDB.delete(StrokeDB.TABLE_STROKE, arg1, arg2);
                break;
            case CHN_CODE:
                String strIndex = arg0.getPathSegments().get(1);
                String strCode = getGBKCode(strIndex);
                if (strCode.length() > 0) {
                    String strWhere = StrokeDB.COLUMN_CODE + " = '" + strCode + "'";
                    if (!TextUtils.isEmpty(arg1))
                        strWhere += " AND (" + arg1 + ')';
                    count = mDB.mstrokeDB.delete(StrokeDB.TABLE_STROKE, strWhere, arg2);
                }
                break;
            default:
                throw new IllegalArgumentException("Unknown URI " + arg0);
        }
        getContext().getContentResolver().notifyChange(arg0, null);
        return count;
    }

    @Override
    public String getType(Uri uri) {
        // TODO Auto-generated method stub
        String str = "";
        switch (uriMatcher.match(uri)){
            case CHN_LIST:
                str = "vnd.android.cursor.dir/vnd.creative.provider";
                break;
            case CHN_CODE:
                str = "vnd.android.cursor.item/vnd.creative.provider";
                break;
            default:
                throw new IllegalArgumentException("Unsupported URI: " + uri);
        }
        return str;
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        // TODO Auto-generated method stub
        long rowID = mDB.mstrokeDB.insert(StrokeDB.TABLE_STROKE, "", values);
        if (rowID > 0) {
            String strCode = values.getAsString(StrokeDB.COLUMN_CODE);
            if (strCode != null && strCode.length() > 0) {
                int nID = getCodeID(strCode);
                Uri _uri = ContentUris.withAppendedId(CONTENT_URI, nID);
                getContext().getContentResolver().notifyChange(_uri, null);
                return _uri;
            }
        }
        throw new SQLException("Failed to insert row into " + uri);
    }

    private static int getCodeID(String strCode) {
        int n = 0;
        try{
            byte[] bData = strCode.getBytes("GBK");
            n = (int)(bData[0] & 0xff);
            int m = (int)(bData[1] & 0xff);
            n += (m << 8);
        }catch(Exception e){
            //Log.d(TAG, ""+e.getMessage());
            n = 0;
        }
        return n;
    }

    public static String getExternalStoragePath() {
        if (android.os.Environment.getExternalStorageDirectory().canWrite())
            return android.os.Environment.getExternalStorageDirectory().getPath();
        return null;
    }

    private static boolean copyDataBaseFileFromAssets(String strDBName) {

         String strTempTarget = mloadPath + File.separator + "temp_" +   strDBName;
         String strTarget = mloadPath + File.separator  + strDBName;

         String strName1 = "cdb/" + strDBName;
         File file = new File(strTempTarget);
         if (file != null && file.exists() && file.isFile()) {
             file.delete();
         }
         if (Strokeutils.saveSmallAssetsFile(mAssetsManager, strName1, strTempTarget, "")) {
            file = new File(strTempTarget);
            if (file != null && file.exists() && file.isFile()) {
                file.renameTo(new File(strTarget));
                return true;
            } else{
                return false;
            }
         } else {
             return false;
         }


    }


    private boolean copyDatabaseFile(String strDBName) {
        int nPos = mLibPath.lastIndexOf('/');
        if (nPos <= 0)
            return false;
        // to check file in SDCard
        String strSDCardPath = getExternalStoragePath();
        String strSource = String.format(DB_SOURCE_PATH, strSDCardPath) + strDBName;
        String strDBPath = mLibPath.substring(0, nPos) + "/databases";
        String strTarget = strDBPath + "/" + strDBName;
//		System.out.printf("\n#### " + strTarget + "#####\n");
        boolean bSucc = false;
        File f = new File(strSource);
        if (f.exists()) {
            // to copy file
            bSucc = Strokeutils.copyFile(strTarget, strSource);
        }
        if (!bSucc) {
            // to check file in /lib folder
            strSource = mLibPath.substring(0, nPos) + "/lib/lib" + strDBName + ".so";
            f = new File(strSource);
            if (f.exists()) {
                // to copy file from /lib folder
                bSucc = Strokeutils.copyFile(strTarget, strSource);
            }
        }
        // to copy file from <package>/assets folder
        if (!bSucc) {
            boolean bFind = false;
            int nSize = (mAssetsDBFile!=null ? mAssetsDBFile.length : 0);
            for(int i=0; i<nSize; i++) {
                String strFile = mAssetsDBFile[i];
                if (strFile.compareTo(strDBName) == 0) {
                    bFind = true;
                    break;
                }
            }
            if (bFind) {
                String strName = "db/" + strDBName;
                bSucc = Strokeutils.saveAssetsFile(mAssetsManager, strName, strTarget);
            } else {
                String strName1 = "cdb/" + strDBName;
                bSucc = Strokeutils.saveSmallAssetsFile(mAssetsManager, strName1, strTarget, "");
                if (!bSucc) {
                    String strName2 = "sdb/" + strDBName;
                    bSucc = Strokeutils.saveSmallAssetsFile(mAssetsManager, strName2, strTarget, ".mp3");
                }
            }
        }
        //debug
//		File ftmp = new File(strTarget);
//		boolean b = ftmp.exists();
//		System.out.printf("\n#### " + strTarget + " IS " + b +"#####\n");
        return bSucc;
    }

    private String GetLoadResourcePath(Context ctx) {
        String strPath = ctx.getFilesDir().getAbsolutePath();
        int nPos = strPath.lastIndexOf('/');
        return strPath.substring(0, nPos+1);
    }

    @Override
    public boolean onCreate() {
        // TODO Auto-generated method stub

/*        mAssetsManager = getContext().getAssets();
        try {
            mAssetsDBFile = mAssetsManager.list("db");
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }*/
/*        try {
            mloadPath = utils.getireadckclocalstrokedatafolder(false, null);
            MyLog.d("ReaderPath  strokepath = " + mloadPath);
        } catch (Exception e) {
            // for future function, the stroke data should be required from net again
            return false;
        }
        mLibPath = mloadPath + "lib";*/

        //checkLoadDB();
        return true;
    }

    public static  boolean checkLoadDB(Context context) {

        mAssetsManager = context.getAssets();
        try {
            mAssetsDBFile = mAssetsManager.list("db");
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        try {
            mloadPath = FileUtil.getireadckclocalstrokedatafolder(true);
            TLog.log("ReaderPath  strokepath = " + mloadPath);
        } catch (Exception e) {
            // for future function, the stroke data should be required from net again
            return false;
        }
        mLibPath = mloadPath + "lib";


        String strSave = mloadPath + "/" + StrokeDB.DATABASE_NAME;
        File file = new File(strSave);
        boolean bCopy = false;
        if (file != null && file.isFile() && file.exists()) {
            mDB = new StrokeDB(context, mloadPath);
            return true;
        } else {
            file = new File(mloadPath);
            if (!file.exists() || !file.isDirectory()) {
                file.mkdir();
            }
            bCopy = copyDataBaseFileFromAssets(StrokeDB.DATABASE_NAME);
        }

        if (bCopy) {
            mDB = new StrokeDB(context, mloadPath);
            return true;
        } else {
            return false;
        }
    }

    public static boolean loadDB(Context context) {
        if (mDB == null) {
            try {
                mloadPath = FileUtil.getireadckclocalstrokedatafolder(true);
            } catch (Exception e) {
                // for future function, the stroke data should be required from net again
                return false;
            }
            String strSave = mloadPath + "/" + StrokeDB.DATABASE_NAME;
            File file = new File(strSave);
            if (file != null && file.isFile() && file.exists()) {
                mDB = new StrokeDB(context, mloadPath);
                return true;
            }
        } else {
            return true;
        }
        return false;
    }


    private int getRowCount() {
        final String strSql = "select count(*) from " + StrokeDB.TABLE_STROKE;
        Cursor c = null;
        try{
            c = mDB.mstrokeDB.rawQuery(strSql, null);
        } catch (Exception e) {
           // Log.d(TAG, ""+e.getMessage());
        }
        if (c == null)
            return 0;
        int nCount = 0;
        if (c.moveToFirst())
            nCount = c.getInt(0);
        c.close();
        return nCount;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        // TODO Auto-generated method stub
        Cursor c = null;
        int nID = uriMatcher.match(uri);
        //Log.d(TAG, "query nID="+nID);
        switch(nID) {
            case CHN_LIST:
                if (selection != null && selection.length() > 0)
                    c = querySelection(projection, selection, selectionArgs, sortOrder);
                break;
            case CHN_CODE:
                String strIndex = uri.getPathSegments().get(1);
                c = queryCode(strIndex, projection, selection, selectionArgs, sortOrder);
                break;
            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
        }
        //---register to watch a content URI for changes---
        if (c != null)
            c.setNotificationUri(getContext().getContentResolver(), uri);
        return c;
    }

    protected Cursor querySelection(String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        Cursor c;
        try{
            // to query result from table
//			if (TextUtils.isEmpty(sortOrder))
//		         sortOrder = StrokeDB.COLUMN_INDEX;
            SQLiteQueryBuilder sqlBuilder = new SQLiteQueryBuilder();
            sqlBuilder.setTables(StrokeDB.TABLE_STROKE);
            c = sqlBuilder.query(mDB.mstrokeDB, projection, selection, selectionArgs, null, null, sortOrder);
        }catch(Exception e){
            e.printStackTrace();
            c = null;
        }
        return c;
    }

    protected static String getGBKCode(String strIndex) {
        try{
            int n = Integer.parseInt(strIndex);
            byte[] b = new byte[2];
            b[0] = (byte)(n & 0xff);
            b[1] = (byte)((n >> 8) & 0xff);
            return new String(b, "GBK");
        }catch(Exception e){
            e.printStackTrace();
        }
        return "";
    }

    protected Cursor queryCode(String strIndex, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        Cursor c;
        try{
            String strCode = getGBKCode(strIndex);
            if (TextUtils.isEmpty(strCode) || strCode.length()!=1) {
               // Log.d(TAG, "code="+strCode);
                return null;
            }
            // to query result from table
//			if (TextUtils.isEmpty(sortOrder))
//		        sortOrder = StrokeDB.COLUMN_INDEX;
            SQLiteQueryBuilder sqlBuilder = new SQLiteQueryBuilder();
            sqlBuilder.setTables(StrokeDB.TABLE_STROKE);
            sqlBuilder.appendWhere(StrokeDB.COLUMN_CODE + " = '" + strCode + "'");
            c = sqlBuilder.query(mDB.mstrokeDB, projection, selection, selectionArgs, null, null, sortOrder);
        }catch(Exception e){
            e.printStackTrace();
            c = null;
        }
        return c;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        // TODO Auto-generated method stub
        int count = 0;
        switch (uriMatcher.match(uri)) {
            case CHN_LIST:
                count = mDB.mstrokeDB.update(StrokeDB.TABLE_STROKE, values, selection, selectionArgs);
                break;
            case CHN_CODE:
                String strIndex = uri.getPathSegments().get(1);
                String strCode = getGBKCode(strIndex);
                if (strCode.length() > 0) {
                    String strWhere = StrokeDB.COLUMN_CODE + " = '" + strCode + "'";
                    if (!TextUtils.isEmpty(selection))
                        strWhere += " AND (" + selection + ')';
                    count = mDB.mstrokeDB.update(StrokeDB.TABLE_STROKE, values, strWhere, selectionArgs);
                }
                break;
            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
        }
        getContext().getContentResolver().notifyChange(uri, null);
        return count;
    }


    // bypass 2014-05-26, to refresh the stroke.db, which is on sdcard, automatically when the internal stroke.db is upgraded, begin:
    private final static String m_ssDatabaseVersionFile = "strokedb.ver";
    private final static String m_ssstrokedbver_Format = "stroke.db version=%d";
    private final static int m_siMenualDbVersion = 2;

    private boolean strokedbisUpgraded() {
        String strversion = mloadPath + /*DB_PATH +*/ "/" + m_ssDatabaseVersionFile;
        File f = new File(strversion);
        if(!f.exists()) {
            try{
                FileOutputStream out = new FileOutputStream(f);
                String scontent = String.format(m_ssstrokedbver_Format, m_siMenualDbVersion);
                byte[] byout = scontent.getBytes();
                if(null != byout && byout.length > 0) {
                    out.write(byout);
                    out.close();
                }
            }catch(Exception e){
                f = new File(strversion);
                try{
                    f.delete();
                }catch(Exception e1){
                }
            }
            return true;
        }
        else{
            try{
                if(f.length() > 0){
                    FileInputStream in = null;
                    byte []buf = new byte[(int)f.length()];
                    try {
                        in = new FileInputStream(strversion);
                        int iread = in.read(buf);
                        in.close();
                        if(iread > 0) {
                            String s = new String(buf);
                            if(!TextUtils.isEmpty(s)) {
                                String[]sinfo = s.split("=");
                                if(2 == sinfo.length && !TextUtils.isEmpty(sinfo[1])){
                                    Integer ii = Integer.parseInt(sinfo[1]);
                                    if(null != ii) {
                                        if(ii.intValue() < m_siMenualDbVersion) {
                                            return true;
                                        }
                                    }
                                }
                            }
                        }
                    } catch (FileNotFoundException e) {
                        e.printStackTrace();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }catch(Exception e){
            }
        }
        return false;
    }
    // bypass 2014-05-26 end.

}
